﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using XXF.BaseService.ServiceCenter.Model;
using XXF.BaseService.ServiceCenter.Service.Protocol;
using XXF.BaseService.ServiceCenter.Service.Server;
using XXF.BaseService.ServiceCenter.SystemRuntime;
using XXF.ProjectTool;
using XXF.Common;

namespace XXF.BaseService.ServiceCenter.Service.Provider
{
    /// <summary>
    /// 服务提供者
    /// </summary>
    public class ServiceProvider : IDisposable
    {
        protected bool _isdispose = false;
        protected Type _registerService;
        protected string _servicenamespace = "";
        protected ServiceContext _context;
        protected BaseServer _server;
        protected ServiceProtocal _protocal;
        protected ServiceHeatBeatProtect protect;
        public ServiceProtocal Protocal { get { return _protocal; } }

        /// <summary>
        /// 注册服务
        /// </summary>
        /// <param name="service"></param>
        public void RegisterProtocol(Type service)
        {
            RegisterProtocol(service.Namespace, service);
        }
        /// <summary>
        /// 注册服务
        /// </summary>
        /// <param name="servicenamespace"></param>
        /// <param name="service"></param>
        public void RegisterProtocol(string servicenamespace, Type service)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(servicenamespace))
                    throw new ServiceCenterException("服务命名空间不能为空");
                _servicenamespace = servicenamespace;
                ProtocolProvider pp = new ProtocolProvider();
                _protocal = pp.From(service);
                _registerService = service;
            }
            catch (Exception exp)
            {
                LogHelper.Error(-1, EnumLogType.Service, string.Format("服务注册协议失败,服务命名空间：{0}", servicenamespace), exp);
                throw exp;
            }
        }
        /// <summary>
        /// 运行服务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="successCallBack">服务运行成功时回调函数</param>
        public void Run<T>(Action successCallBack = null)
        {
            try
            {
                while (_isdispose == false)
                {
                    //获取系统配置
                    SystemConfigHelper.Load();
                    tb_service_model serviceModel = null;
                    SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                    {
                        //获取服务
                        Dal.tb_service_dal servicedal = new Dal.tb_service_dal();
                        serviceModel = servicedal.Get(c, _servicenamespace);
                    });
                    if (serviceModel == null)
                        throw new ServiceCenterException(string.Format("当前服务{0}未在服务中心站点中注册,请联系管理员在服务中心中注册", _servicenamespace));
                    //获取本机可用端口
                    int canuseport = (_context != null ? _context.NodeModel.port : CommonHelper.FindNextAvailableTCPPort(SystemConfigHelper.NodeMinPort, SystemConfigHelper.NodeMaxPort));
                    //启动服务
                    if (serviceModel.servicetype == (byte)EnumServiceType.Thrift)
                    {
                        _server = new ThriftServer();
                        _server.Run<T>(canuseport, _protocal, _context, () =>
                        {
                            //重启不刷新服务信息，排除重启
                            if (_context == null)
                            {
                                RegisterContext(_server, canuseport);
                                if (successCallBack != null)
                                    successCallBack();
                            }
                            else
                            {
                                _context.Server = _server;
                            }
                        });
                    }
                    else
                    {
                        throw new ServiceCenterException(string.Format("当前服务不支持{0}协议", ((EnumServiceType)serviceModel.servicetype).ToString()));
                    }

                }
            }
            catch (Exception exp)
            {
                LogHelper.Error(-1, EnumLogType.Service, string.Format("服务注册失败,服务命名空间：{0}", _servicenamespace), exp);
                throw exp;
            }
        }

        private void RegisterContext(BaseServer server, int canuseport)
        {
            try
            {
                // 建立上下文
                ServiceContext context = new ServiceContext();
                SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                {
                    try
                    {
                        c.BeginTransaction();
                        context.ServiceProvider = this;
                        context.Server = server;
                        _context = context;
                        //获取服务
                        Dal.tb_service_dal servicedal = new Dal.tb_service_dal();
                        context.ServiceModel = servicedal.Get(c, _servicenamespace);

                        if (context.ServiceModel == null)
                            throw new ServiceCenterException("当前服务未在服务中心站点中注册,请联系管理员在服务中心中注册");
                        //注册服务节点
                        tb_node_model nodemodel = new tb_node_model();
                        nodemodel.boostpercent = 10;//默认权重
                        nodemodel.processcpuper = 0;
                        nodemodel.errorcount = 0;
                        nodemodel.filesize = CommonHelper.CurrentDirSize();
                        nodemodel.processthreadcount = 0;
                        nodemodel.visitcount = 0;
                        nodemodel.interfaceversion = CommonHelper.GetCustomVersion(_registerService.Assembly);
                        //var json = JsonConvert.SerializeObject();
                        nodemodel.ip = CommonHelper.GetDefaultIP();
                        nodemodel.memorysize = 0;
                        nodemodel.port = canuseport;
                        nodemodel.protocoljson = JsonConvert.SerializeObject(_protocal);
                        nodemodel.runstate = (byte)EnumRunState.Running;
                        nodemodel.serviceid = context.ServiceModel.id;
                        nodemodel.servicenamespace = context.ServiceModel.servicenamespace;
                        nodemodel.sessionid = CommonHelper.CreateSessionID();
                        Dal.tb_node_dal nodedal = new Dal.tb_node_dal();
                        if (nodedal.Edit(c, nodemodel) == false)
                        {
                            nodedal.Add(c, nodemodel);
                        }
                        context.NodeModel = nodedal.Get(c, nodemodel.sessionid);

                        if (context.NodeModel == null)
                            throw new ServiceCenterException("当前服务节点未注册成功");
                        //注册服务心跳
                        protect = new ServiceHeatBeatProtect(context);
                        context.HeatBeatProtect = protect;
                        //更新服务最后更新时间
                        Dal.tb_service_dal servicedal2 = new Dal.tb_service_dal();
                        servicedal2.UpdateLastUpdateTime(c, context.ServiceModel.id);
                        c.Commit();

                    }
                    catch (Exception exp)
                    {
                        c.Rollback();
                        try { Close(); }
                        catch { }
                        throw exp;
                    }
                });
                //注册监控
                context.Performance = new Performance.ThriftPerformance(context);
                LogHelper.Log(context.ServiceModel.id, EnumLogType.Service, string.Format("服务注册启动成功,服务命名空间：{0}", _servicenamespace));
            }
            catch (Exception exp)
            {
                LogHelper.Error(-1, EnumLogType.Service, string.Format("服务注册启动成功,但注册上下文失败,服务命名空间：{0}", _servicenamespace), exp);
                throw exp;
            }
        }

        private void UnRegisterContext()
        {
            try
            {
                SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                {
                    //注销节点
                    Dal.tb_node_dal nodedal = new Dal.tb_node_dal();
                    nodedal.Delete(c, _context.NodeModel.sessionid);
                    //更新服务最后更新时间
                    Dal.tb_service_dal servicedal2 = new Dal.tb_service_dal();
                    servicedal2.UpdateLastUpdateTime(c, _context.ServiceModel.id);

                });
                _context = null;
            }
            catch (Exception exp)
            {
                LogHelper.Error(-1, EnumLogType.Service, string.Format("服务取消上下文注册失败,服务命名空间：{0}", _servicenamespace), exp);
                throw exp;
            }
        }

        private void Close()
        {
            if (_server != null)
            {
                try
                {
                    _server.Stop();
                }
                catch { }
            }
            if (_context != null && _context.HeatBeatProtect != null)
            {
                try
                {
                    _context.HeatBeatProtect.Dispose();
                }
                catch { }
            }
            try
            {
                UnRegisterContext();
            }
            catch (Exception exp)
            {
            }

            _context = null;
        }

        public void Dispose()
        {
            if (null != protect)
            {
                protect.Dispose();
            }
            _isdispose = true;
            Close();

        }
    }
}
